/**
 * Browse.java
 * Purpose: Controller
 *
 * @version 1.0 4/28/11
 * @author Islam Al-Aarag
 */
package controllers;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;

import models.ActionItem;
import models.Comment;
import models.DuplicateMark;
import models.EEntity;
import models.Idea;
import models.MergeRequest;
import models.Notification;
import models.Organization;
import models.Plan;
import models.RelatedEntities;
import models.Role;
import models.RoleInEntity;
import models.RoleInEntity;
import models.RoleInOrganization;
import models.Tag;
import models.Topic;
import models.TopicRelationNames;
import models.User;
import play.db.jpa.JPA;
import play.modules.search.Search;
import play.mvc.*;

public class Browse extends Controller {
	/**
	 * A method to view a non secret organization and secret organizations for
	 * members. It first get the user name from the session and depending on
	 * that and the organization it renders one of 3 values for variable view 0:
	 * The id of the organization is not correct and it is not even there 1: The
	 * user is either not logged in or not a member and it is a secret
	 * organization 2: The user can view the organization It also renders the
	 * organization to be viewed
	 * 
	 * @author Islam Al-Aarag
	 * @param orgID
	 *            the id of the organization that needs to be viewed
	 * 
	 */
	public static void viewOrganization(long orgID) {
		String userName = session.get("username");
		User user = null;
		if (userName != null)
			user = User.find("byUserName", userName).first();
		Organization org = Organization.find("byID", orgID).first();
		int view;
		if (org == null)
			view = 0;
		else if (org.isSecret()
				&& (user == null || (!org.isMember(user.id) && !user
						.isSysteAdmin())))
			view = 1;
		else
			view = 2;
		boolean isLead = false;
		boolean isFound = false;
		if (user != null && org != null) {
			isFound = false;
			if ((user.isOrganizationLead(orgID) && org.isSecret())
					|| (user.isOrganizationLead(orgID) && org.isPrivate()))
				isFound = true;
		}
		if (isFound)
			isLead = true;
		boolean isAllowedToFollow = false;
		boolean isAllowedToUnfollow = false;
		if (user != null) {
			if (user.isOrganizationLead(orgID)) {
				isAllowedToFollow = false;
				isAllowedToUnfollow = false;
			} else {
				if (user.hasFollowedOrganization(orgID))
					isAllowedToUnfollow = true;
				else {
					if (org != null) {
						if (org.privacyStatus == 0)
							isAllowedToFollow = true;
						if (org.isPrivate() && org.isMember(user.id))
							isAllowedToFollow = true;
						if (org.isSecret())
							isAllowedToFollow = true;
					}
				}
			}
			if (org != null)
				org.numberOfView++;

		}

		// added by Shady
		boolean isOrganizationLead = false;
		if (user != null && user.isOrganizationLead(orgID)
				|| (user!=null && org != null && org.isAsOrganizationLead(user.id))
				|| (user!=null && user.isSysteAdmin())) {
			isOrganizationLead = true;
		}

		List<User> ideaDevelopers = null;

		if (user != null) {
			if (isOrganizationLead && org.getIdeaDevelopers() != null) {
				ideaDevelopers = org.getIdeaDevelopers();
			}
		}
		// end shady's addition

		boolean organizationLead = false;
		boolean allowTagsCreation = false;
		if (user != null && org != null) {
			if (user.isOrganizationLead(orgID)) {
				organizationLead = true;
				if (org.allowingTagCreationForDevelopers == true) {
					allowTagsCreation = true;
				}
			}
		}
		// For Omar Darwish Work
		boolean allowLeadPrivileges = false;
		boolean allowRemoveLeadPrivileges = false;
		boolean isSystemAdmin = false;
		boolean onlyLead = false;
		if (userName != null && user != null && org != null) {
			isSystemAdmin = user.isSysteAdmin();
			allowLeadPrivileges = (org.getOrganizationLead() != null && user.id == org
					.getOrganizationLead().id)
					|| org.isAsOrganizationLead(user.id) || isSystemAdmin;
			allowRemoveLeadPrivileges = (org.getOrganizationLead() != null && user.id == org
					.getOrganizationLead().id) || isSystemAdmin;
			onlyLead = (org.getOrganizationLead() != null && user.id == org
					.getOrganizationLead().id);

		}

		// For Johannes Schmidt
		boolean isOrganizer = false;
		for (EEntity entity : org.entities) {
			if (user != null && user.isOrganizer(entity.id))
				isOrganizer = true;
		}
		render(org, view, isLead, isAllowedToFollow, isAllowedToUnfollow,
				organizationLead, allowTagsCreation, ideaDevelopers,
				allowLeadPrivileges, allowRemoveLeadPrivileges, isSystemAdmin,
				isOrganizer);

	}

	/**
	 * A method to view a and entity of non secret organization and that secret
	 * organizations for members.It first get the user name from the session and
	 * depending on that and the organization of the entity it renders one of 3
	 * values for variable view 0: The id of the organization is not correct and
	 * it is not even there 1: The user is either not logged in or not a member
	 * and it is a secret organization 2: The user can view the organization It
	 * also renders the entity to be viewed
	 * 
	 * @author Islam Al-Aarag
	 * 
	 * @param entityID
	 *            the id of the entity that needs to be viewed
	 * 
	 */
	public static void viewEntity(long entityID) {
		Organization org = null;
		String userName = session.get("username");
		User user = null;
		boolean isAllowedToPost = false;
		boolean isAllowedToRelate = false;
		boolean viewLock = false;
		if (userName != null)
			user = User.find("byUserName", userName).first();
		EEntity entity = EEntity.find("byID", entityID).first();
		int view;
		if (entity == null)
			view = 0;
		else {
			org = entity.organization;
			if (org.isSecret()
					&& (!org.isMember(user.id) && !user.isSysteAdmin()))
				view = 1;
			else {
				view = 2;
				if (user != null) {
					if (user.isOrganizationLead(org.id)
							|| (user.isOrganizer(entity.id) && (org.isSecret()
									|| org.isPrivate() || org.privacyStatus == 0))
							|| (org.isAsOrganizationLead(user.id))
							|| user.isSysteAdmin())
						isAllowedToPost = true;
				}
				if (user != null && user.isOrganizationLead(org.id)
						&& entity != null && entity.isLock == false) {
					isAllowedToRelate = true;
				}
				if (user != null && user.isOrganizationLead(org.id)
						&& entity != null) {
					viewLock = true;
				}
			}
		}
		boolean isMember = false;
		if (user != null && entity != null
				&& entity.isMember(entity.id, user.id)
				&& !user.isOrganizer(entityID)
				&& !user.isOrganizationLead(entity.organization.id)) {
			isMember = true;
		}
		long userID = user == null ? -1 : user.id;

		List<User> members = new ArrayList<User>();
		if (entity != null)
			for (int i = 0; i < entity.rolesAndUsers.size(); i++) {
				members.add(entity.rolesAndUsers.get(i).user);
			}
		boolean isAllowedToFollow = false;
		boolean isAllowedToUnfollow = false;
		if (user != null && entity != null) {
			Organization organization = entity.organization;
			if (user.isOrganizer(entity.id)
					|| user.isOrganizationLead(organization.id)) {
				isAllowedToFollow = false;
				isAllowedToUnfollow = false;
			} else {
				if (user.hasFollowedEntity(entityID)) {
					if (!user.hasFollowedOrganization(organization.id))
						isAllowedToUnfollow = true;
				} else {
					if (!user.hasFollowedOrganization(organization.id)) {
						if (organization.privacyStatus == 0)
							isAllowedToFollow = true;
						if (organization.isPrivate()
								&& organization.isMember(user.id))
							isAllowedToFollow = true;
						if (organization.isSecret())
							isAllowedToFollow = true;
					}
				}
			}
		}
		if (entity != null)
			entity.numberOfView++;

		// Added by Sherif Ayad
		List<Plan> allPlans = Plan.findAll();
		List<Plan> entityPlans = new ArrayList<Plan>();
		for (int i = 0; i < allPlans.size(); i++) {
			List<Idea> planIdeas = allPlans.get(i).ideas;
			if (planIdeas.size() > 0) {
				if (planIdeas.get(0).topic.entity.id == entityID)
					entityPlans.add(allPlans.get(i));
			}
		}

		// added by Yomna El Rashidi
		List<EEntity> relatedEntities = entity != null ? Relations
				.getRelatedWithEntities(entityID) : new ArrayList<EEntity>();
		List<EEntity> allowedToRelateToList = entity != null ? Relations
				.getallowedToRelateEntities(entityID, org)
				: new ArrayList<EEntity>();

		// Omar Darwish Work
		boolean isOrganizer = false;
		if (userName != null && user != null && org != null && entity != null) {
			isOrganizer = entity.getOrganizers().contains(user);
		}
		boolean isOrganizationLead = false;
		boolean isSystemAdmin = false;

		if (user != null) {
			if (user == org.getOrganizationLead())
				isOrganizationLead = true;
			if (user.isSysteAdmin())
				isSystemAdmin = true;
		}
		int countTopicsinEntity = 0;
		if (entity != null) {
			for (Topic topic : entity.topics) {
				if (topic.status == 0 || topic.status == 1 || topic.status == 4)
					if (!(!isAllowedToPost && topic.status == 4)) {
						countTopicsinEntity++;
					}
			}
		}
		render(entity, view, isAllowedToPost, members, isAllowedToFollow,
				isAllowedToUnfollow, entityPlans, isMember, userID,
				relatedEntities, allowedToRelateToList, isAllowedToRelate,
				isOrganizer, isOrganizationLead, viewLock, isSystemAdmin,
				countTopicsinEntity);
	}

	/**
	 * A method to view a topic that belongs to an entity of a non secret
	 * organization and those of secret organizations for members. It first get
	 * the user name from the session and depending on that and the organization
	 * of the entity of the topic it renders one of 3 values for variable view
	 * 0: The id of the organization is not correct and it is not even there 1:
	 * The user is either not logged in or not a member and it is a secret
	 * organization 2: The user can view the organization It also renders the
	 * topic to be viewed
	 * 
	 * @author Islam Al-Aarag
	 * 
	 *         this method also views the Related Topics for this Topic
	 * 
	 * @param topicID
	 *            the id of the topic that needs to be viewed
	 * 
	 */
	public static void viewTopic(long topicID) {
		String userName = session.get("username");
		User user = null;
		if (userName != null)
			user = User.find("byUserName", userName).first();
		Topic topic = Topic.find("byID", topicID).first();
		int view;
		int ifCreator = 0;
		int ifOrganizer = 0;

		boolean isUpperManagement = false;

		if (topic == null)
			view = 0;
		else {
			if (user != null) {
				if (user.createdTopics.contains(topic))
					ifCreator = 3;
				if (user.isOrganizer(topic.entity.id))
					ifOrganizer = 3;
			}

			Organization org = topic.entity.organization;
			if (org.isSecret()
					&& (user != null && !org.isMember(user.id) && !user
							.isSysteAdmin()))
				view = 1;

			else if (user == null)
				view = 2;

			else {
				view = 2;
				if (user != null) {
					if (user.isOrganizationLead(org.id)
							|| user.isOrganizer(topic.entity.id)
							|| (org.isAsOrganizationLead(user.id))
							|| user.isSysteAdmin())
						isUpperManagement = true;

				}
			}
		}

		List<Topic> allTopics = Topic.find("byIsLock", false).fetch();

		List<Topic> relatedTopics = topic != null ? topic.relatedTopicList
				: new ArrayList<Topic>();

		// System.out.println(relatedTopics.size());
		List<TopicRelationNames> topicRelationNames = TopicRelationNames
				.findAll();

		allTopics.remove(topic);

		for (int i = 0; i < relatedTopics.size(); i++) {
			for (int j = 0; j < allTopics.size(); j++) {
				if (relatedTopics.get(i).id == allTopics.get(j).id)
					allTopics.remove(j);
			}
		}

		boolean isAllowedToFollow = false;
		boolean isAllowedToUnfollow = false;
		boolean isOrganizer = false;
		if (topic != null) {
			EEntity topicEntity = topic.entity;
			Organization topicOrganization = topicEntity.organization;

			if (user != null)
				if (topicEntity.getOrganizers().contains(user)
						|| topicEntity.organization.getOrganizationLead()
								.equals(user)
						|| topicEntity.organization
								.isAsOrganizationLead(user.id)) {
					isOrganizer = true;
				}

			if (user != null) {
				if (user.isOrganizationLead(topicOrganization.id)
						|| user.isOrganizer(topicEntity.id)) {
					isAllowedToFollow = false;
					isAllowedToUnfollow = false;
				} else {
					if (user.hasFollowedTopic(topicID)) {
						if (!user.hasFollowedOrganization(topicOrganization.id)
								&& !user.hasFollowedEntity(topicEntity.id))
							isAllowedToUnfollow = true;
					} else {
						if (!user.hasFollowedEntity(topicEntity.id)
								&& !user.hasFollowedOrganization(topicOrganization.id)) {
							if (topicOrganization.privacyStatus == 0)
								isAllowedToFollow = true;
							if (topicOrganization.isPrivate()
									&& topicOrganization.isMember(user.id))
								isAllowedToFollow = true;
							if (topicOrganization.isSecret())
								isAllowedToFollow = true;
						}
					}
				}
			}
		}
		if (topic != null)
			topic.numberOfView++;
		boolean allowedToRate = false;
		if (user != null && topic != null) {
			if ((topic.entity.organization.isSecret() || topic.entity.organization
					.isPrivate())) {
				if (topic.entity.organization.isMember(user.id)
						&& topic.isAllowedToBeViewedToIdeaDevelopers()) {
					allowedToRate = true;
				}
			} else if (topic.isAllowedToBeViewedToIdeaDevelopers()) {
				allowedToRate = true;
			}
		}
		int countIdeasinTopic = 0;
		if (topic != null)
			for (Idea idea : topic.ideas) {
				if (!((idea.isHidden) && !(isUpperManagement))
						&& !(idea.isDraft)) {
					countIdeasinTopic++;
				}
			}
		render(topic, view, isUpperManagement, allTopics, relatedTopics,
				isAllowedToFollow, isAllowedToUnfollow, topicRelationNames,
				ifCreator, isOrganizer, ifOrganizer, allowedToRate,
				countIdeasinTopic);
	}

	/**
	 * A method to view an idea in a topic that belongs to an entity of a non
	 * secret organization and those of secret organizations for members. It
	 * first get the user name from the session and depending on that and the
	 * organization of the entity of topic of the idea it renders one of 3
	 * values for variable view 0: The id of the organization is not correct and
	 * it is not even there 1: The user is either not logged in or not a member
	 * and it is a secret organization 2: The user can view the organization It
	 * also renders the idea to be viewed
	 * 
	 * @author Islam Al-Aarag
	 * 
	 * @param ideaID
	 *            the id of the idea that needs to be viewed
	 * 
	 */
	public static void viewIdea(long ideaID) {
		String userName = session.get("username");
		User user = null;
		if (userName != null)
			user = User.find("byUserName", userName).first();
		Idea idea = Idea.find("byID", ideaID).first();
		int view;
		boolean isOrganizer = false;
		boolean isAllowedToTag = false;
		boolean isAllowedToDelete = false;
		if (idea == null)
			view = 0;
		else {
			Organization org = idea.topic.entity.organization;
			if (org.isSecret()
					&& (!org.isMember(user.id) && !user.isSysteAdmin()))
				view = 1;
			else {
				view = 2;
				if (user != null
						&& (user.isOrganizationLead(org.id)
								|| user.isOrganizer(idea.topic.entity.id)
								|| user.id == idea.creator.id
								|| (org.isAsOrganizationLead(user.id)) || user
								.isSysteAdmin())) {
					if (user.blocked == false) {
						isAllowedToTag = true;
						if (idea.plans.isEmpty()) {
							isAllowedToDelete = true;
						}
					}
				}
				if (user != null) {
					for (RoleInEntity entityRole : idea.topic.entity.rolesAndUsers) {
						if (entityRole.role.description.toLowerCase().contains(
								"organizer")
								&& user.rolesAndEntities.contains(entityRole)) {
							isOrganizer = true;
							break;
						}
					}
					if (!isOrganizer) {
						Role organizationRole = RoleInOrganization.findRole(
								idea.topic.entity.organization, user);
						if (organizationRole != null
								&& organizationRole.description.toLowerCase()
										.contains("lead")) {
							isOrganizer = true;
						}
					}
					if (!isOrganizer) {
						if (user.isSysteAdmin()
								|| idea.topic.entity.organization
										.isAsOrganizationLead(user.id)) {
							isOrganizer = true;
						}
					}

				}
			}
		}
		// isOrganizer = true;
		String priorityMsg = (view != 0) ? getPriorityMsg(idea.priority)
				: getPriorityMsg(-1);

		if (idea != null)
			idea.numberOfView++;

		boolean isOrgLead = user != null && idea != null
				&& user.isOrganizationLead(idea.topic.entity.organization.id);
		boolean isRquestedbyUser = false;
		if (user != null) {
			for (MergeRequest request : user.mergeRequestsSent) {
				if (request.firstIdea.equals(idea)
						|| request.secondIdea.equals(idea)) {
					isRquestedbyUser = true;
					break;
				}
			}
		}
		boolean allowedToRate = false;
		if (user != null && idea != null) {
			if ((idea.featuredIn.isSecret() || idea.featuredIn.isPrivate())) {
				if (idea.featuredIn.isMember(user.id)
						&& idea.isAllowedToBeViewedToIdeaDevelopers()) {
					allowedToRate = true;
				}
			} else if (idea.isAllowedToBeViewedToIdeaDevelopers()) {
				allowedToRate = true;
			}
		}
		// added by abdalla
		boolean isAllowedTopromote = idea != null
				&& Application.isAllowToPromote(ideaID);
		boolean isCreatedByUser = idea != null && idea.creator.equals(user);

		render(idea, view, priorityMsg, isOrganizer, isAllowedToTag, isOrgLead,
				isRquestedbyUser, isAllowedToDelete, isAllowedTopromote,
				isCreatedByUser, allowedToRate);

	}

	/**
	 * @author Jonas Wilhelm
	 * 
	 *         Method is used to view all details of an actionItem
	 * 
	 * @param itemID
	 *            ID of the item to be shown
	 * 
	 **/

	public static void viewActionItem(long itemId) {
		ActionItem item = ActionItem.findById(itemId);

		render(item);
	}

	public static void viewCreateIdea(long userID, long topicID) {
		render(userID, topicID);
	}

	/**
	 * @author AkrAmAtion
	 * 
	 *         A method that is used to view a message corresponding to a given
	 *         priority level of an {@link Idea}
	 * 
	 * @param priority
	 *            an integer representing the priority level from 0 to 2 (low,
	 *            normal, high)
	 * 
	 * @return a {@link String} message representing the priority level as it
	 *         will be displayed on the viewIdea page
	 * */
	public static String getPriorityMsg(int priority) {
		String priorityVal;
		if (priority == 0)
			priorityVal = "Low";
		else if (priority == 1)
			priorityVal = "Normal";
		else if (priority == 2)
			priorityVal = "High";
		else
			priorityVal = "Invalid or Unknown Priority";
		priorityVal += " Level.";
		return priorityVal;
	}

	/**
	 * A method to render the authorization status, ideaID to the prioritizeIdea
	 * page.
	 * 
	 * @author AkrAmAtion
	 * @param userID
	 *            is the ID of the user requesting to prioritize an idea.
	 * @param ideaID
	 *            is the ID of the idea of which the priority level is to be
	 *            changed.
	 * */
	public static void prioritizeIdea(long ideaID) {
		String userName = session.get("username");
		User user = null;
		long userID = -1;
		if (userName != null)
			user = User.find("byUsername", userName).first();
		if (user != null)
			userID = user.id;
		Idea idea = Idea.findById(ideaID);
		boolean authorized = false;
		if (idea != null && user != null) {
			authorized = user.isSysteAdmin()
					|| idea.topic.entity.organization
							.isAsOrganizationLead(userID);
			if (!authorized)
				for (RoleInEntity entityRole : idea.topic.entity.rolesAndUsers) {
					if (entityRole.user.id == userID
							&& entityRole.role.description.toLowerCase()
									.contains("organizer")) {
						authorized = true;
					}
				}
			if (!authorized)
				for (RoleInOrganization orgRole : idea.topic.entity.organization.rolesAndUsers) {
					if (orgRole.user.id == userID
							&& orgRole.role.description.toLowerCase().contains(
									"lead")) {
						authorized = true;
					}
				}
		}

		else
			ideaID = -1;
		// authorized = true;
		render(authorized, ideaID, idea);
	}

	/**
	 * A method that is to be called by a form in the view of
	 * prioritizeIdea.html page.
	 * 
	 * @author AkrAmAtion
	 * @param idea
	 *            is the {@link Idea} that is to be prioritized.
	 * @param priroity
	 *            is the integer number that represents the priority
	 */
	public static void setPriority(long ideaID, int priority) {
		Idea idea = Idea.findById(ideaID);
		idea.priority = priority;
		idea.save();
		viewIdea(ideaID);
	}

	/**
	 * @author AkrAmAtion
	 * 
	 *         A method used to render the view by which an idea developer can
	 *         mark an idea as duplicate with other ideas under the same topic.
	 * 
	 * @param ideaID
	 *            the id of the ID that should be marked as duplicate
	 * */
	public static void markAsDuplicate(long ideaID) {
		HashMap<Idea, Boolean> wasFound = new HashMap<Idea, Boolean>();
		String userName = session.get("username");
		User user = null;
		long userID = -1;
		boolean authorized = false;
		if (userName != null)
			user = User.find("byUserName", userName).first();
		if (user != null)
			userID = user.id;
		Idea idea = Idea.findById(ideaID);
		if (idea != null
				&& userID != -1
				&& !user.blockedEntities.contains(idea.topic.entity)
				&& !user.blockedOrganizations
						.contains(idea.topic.entity.organization)) {
			authorized = idea.topic.entity.organization
					.isAsOrganizationLead(userID) || user.isSysteAdmin();
			if (!authorized)
				for (RoleInOrganization orgRole : idea.topic.entity.organization.rolesAndUsers) {
					if (orgRole.user.id == userID) {
						authorized = true;
						break;
					}
				}
			if (!authorized) {
				for (RoleInEntity entityRole : idea.topic.entity.rolesAndUsers) {
					if (entityRole.user.id == userID) {
						authorized = true;
						break;
					}
				}
			}
		} else
			ideaID = -1;
		// authorized = true;
		if (authorized) {
			for (DuplicateMark dup : idea.duplicateMarksAsMarked) {
				wasFound.put(dup.original, true);
			}
			for (Idea duplicateIdea : idea.duplicateIdeas) {
				wasFound.put(duplicateIdea, true);
			}
		}
		render(authorized, idea, user, wasFound);
	}

	/**
	 * @author AkrAmAtion
	 * 
	 *         A method that is called by the view 'markAsDuplicate' to mark an
	 *         idea (the one specified by the id ideaID) as duplicate to the
	 *         original ideas that were input and stored in the Controller
	 *         params. A DuplicateMark record is added to the database upon
	 *         calling this method correctly with valid user authorization.
	 * 
	 * @param ideaID
	 *            is the id of the idea that is to be marked as duplicate.
	 * */
	public static void addDuplicateMark(long ideaID) {
		String userName = session.get("username");
		User user = null;
		Idea toMark = Idea.findById(ideaID);
		if (userName != null)
			user = User.find("byUsername", userName).first();
		if (user != null) {

			if (toMark != null
					&& !toMark.topic.entity.blockedFromEntity.contains(user)
					&& !toMark.topic.entity.organization.blockedusers
							.contains(user)) {
				boolean authorized = false;
				for (RoleInEntity entityRole : user.rolesAndEntities) {
					if (entityRole.entity.equals(toMark.topic.entity)) {
						authorized = true;
						break;
					}
				}
				if (!authorized)
					return;
				String[] ids = params.getAll("ids");
				if (ids != null) {
					long[] originalIDs = new long[ids.length];
					for (int i = 0; i < ids.length; i++) {
						originalIDs[i] = Long.parseLong(ids[i]);
					}
					play.cache.Cache
							.safeSet("originalIDs", originalIDs, "30mn");
					for (int i = 0; i < originalIDs.length; i++) {
						Idea original = null;
						original = Idea.findById(originalIDs[i]);
						if (original != null) {
							DuplicateMark dup = new DuplicateMark(user, toMark,
									original).save();
						}
					}
				}
			}
		}
		viewIdea(ideaID);
	}

	/**
	 * method hideIdea take long ideaID and hide the idea
	 * 
	 * @author 7ablas
	 * @param long ideaID
	 */
	public static void hideIdea(long ideaID) {
		Idea idea = Idea.findById(ideaID);
		if (idea != null) {
			User owner1 = idea.creator;
			List<User> owner = new ArrayList();
			owner.add(owner1);
			String title = idea.title;

			long id = idea.topic.id;
			String userName = session.get("username");
			if (userName != null) {
				User user = User.find("userName", userName).first();
				idea.isHidden = true;
				idea.save();
				new Notification("Your idea " + title + " has been hidden",
						ideaID, 17, user, owner).save();
				Application.sendMail("your idea " + title + " has been hidden",
						"hidden topic", owner);
				Browse.viewTopic(id);
			}
		}
	}

	/**
	 * method showIdea take long ideaID and show the idea
	 * 
	 * @author 7ablas
	 * @param long ideaID
	 */
	public static void showIdea(long ideaID) {
		Idea idea = Idea.findById(ideaID);
		if (idea != null) {
			long id = idea.topic.id;
			String userName = session.get("username");
			if (userName != null) {
				User user = User.find("userName", userName).first();
				idea.isHidden = false;
				idea.save();
				Browse.viewTopic(id);
			}
		}
	}

	/**
	 * method promote request take long topicID and promote this request to be a
	 * topic by changing the status from 3:1
	 * 
	 * @author 7ablas
	 * @param long topicID
	 */
	public static void promoteRequest(long topicID, String desc, String name) {

		String userName = session.get("username");
		if (userName != null) {
			User user = User.find("userName", userName).first();

			Topic topic = Topic.findById(topicID);
			if (topic != null && user != null) {
				if (user.isOrganizationLead(topic.entity.organization.id)
						|| user.isOrganizer(topic.entity.id)) {
					topic.status = 1;
					topic.name = name;
					topic.description = desc;

					topic.save();
					LinkedList<User> toBeNotified = new LinkedList<User>();
					for (User user2 : topic.entity.followingUsers) {
						if (!toBeNotified.contains(user2))
							toBeNotified.add(user2);
					}
					for (User user2 : topic.entity.organization.followingUsers) {
						if (!toBeNotified.contains(user2))
							toBeNotified.add(user2);
					}

					Notification newNotification = new Notification(
							"A new topic has been added to Entity "
									+ topic.entity.id, topic.id, 11,
							topic.creator, toBeNotified);
					newNotification.timeStamp = new Date();
					newNotification.save();

					if (topic.creator.isOrganizer(topic.entity.id)) {

						topic.creator.followedTopics.add(topic);
						topic.followingUsers.add(topic.creator);
						topic.creator.save();
						topic.save();
					}

					Browse.viewTopic(topicID);
				}
			}
		}
	}

	/**
	 * method delete topic deletes topic if it has no ideas posted on it
	 * 
	 * @author hablas
	 * @param topicID
	 */
	public static void deleteTopic(long topicID) {
		String userName = session.get("username");
		if (userName != null) {
			User user = User.find("userName", userName).first();

			Topic topic = Topic.findById(topicID);
			if (topic == null || user == null) {

			} else {

				String name = topic.name;
				long entityID = topic.entity.id;
				User creator = topic.creator;
				List<User> creator1 = new ArrayList();
				creator1.add(creator);
				if (topic != null) {
					if (user.isOrganizationLead(topic.entity.organization.id)
							|| user.isOrganizer(topic.entity.id)) {
						if (topic.ideas.isEmpty()) {
							topic.cascadeDelete();
							new Notification("Your topic has been deleted",
									topicID, 16, user, creator1).save();
							Application.sendMail("your topic " + name
									+ " has been deleted", "Deleted topic",
									creator1);
							flash.success("Topic" + " " + name + " "
									+ "has been deleted succesfuly");
							viewEntity(entityID);
						} else {
							flash.error("you can't delete this topic as it has ideas posted on it");
							viewTopic(topicID);
						}
					}
				}
			}
		}
	}

	/**
	 * method close request take long topicID and close this request to be a
	 * topic by changing the status from 3:2
	 * 
	 * @author 7ablas
	 * @param long topicID
	 */
	public static void closeTopic(long topicID) {

		String userName = session.get("username");
		if (userName != null) {
			User user = User.find("userName", userName).first();

			Topic topic = Topic.findById(topicID);
			if (topic != null && user != null) {
				if (user.isOrganizationLead(topic.entity.organization.id)
						|| user.isOrganizer(topic.entity.id)) {
					topic.status = 2;
					topic.save();

				}
			}
		}
		Browse.viewTopic(topicID);
	}

	/**
	 * method disapprove request take long topicID and delete this request
	 * 
	 * @author 7ablas
	 * @param long topicID
	 */
	public static void disapproveRequest(long topicID) {

		String userName = session.get("username");
		if (userName != null) {
			User user = User.find("userName", userName).first();

			Topic topic = Topic.findById(topicID);
			if (topic != null && user != null) {
				if (user.isOrganizationLead(topic.entity.organization.id)
						|| user.isOrganizer(topic.entity.id)) {
					topic.status = 2;
					topic.cascadeDelete();
					Browse.viewTopic(topicID);
				}
			}
		}
	}

	/**
	 * A method that given an entity id, view the requested topic to the
	 * organization lead/organizer so that they can be promoted to topics or
	 * rejected
	 * 
	 * @author Islam Al-Aarag
	 * @param entityID
	 *            the id of the entity in which requested topics should be
	 *            viewed
	 */
	public static void viewRequests(long entityID) {
		EEntity entity = EEntity.find("byID", entityID).first();
		String userName = session.get("username");
		boolean isAllowed = false;
		if (userName != null) {
			User user = User.find("byUserName", userName).first();
			if (user != null) {
				isAllowed |= user.isOrganizationLead(entity.organization.id);
				isAllowed |= user.isOrganizer(entityID);
			}
		}
		List<Topic> requestedTopics = Topic.find(
				"select t from Topic t where t.entity.id=" + entityID
						+ "and t.status=3").fetch();
		render(requestedTopics, isAllowed);
	}

	/**
	 * renders to the organizer or organization lead a list of the duplicate
	 * marks associated with the specified topic
	 * 
	 * @author AkrAmAtion
	 * 
	 * @param topicID
	 *            the id of the topic where the duplicate marks are to be
	 *            viewed.
	 */
	public static void viewDuplicateMarks(long topicID) {
		boolean authorized = false;
		Topic topic = null;
		topic = Topic.findById(topicID);
		List<DuplicateMark> duplicateMarks = new LinkedList<DuplicateMark>();
		if (topic != null) {
			String userName = session.get("username");
			User user = null;
			long userID = -1;
			if (userName != null)
				user = User.find("byUsername", userName).first();
			if (user != null)
				userID = user.id;

			if (topic != null && user != null) {
				authorized = user.isSysteAdmin()
						|| topic.entity.organization
								.isAsOrganizationLead(userID);
				if (!authorized)
					for (RoleInEntity entityRole : topic.entity.rolesAndUsers) {
						if (entityRole.user.id == userID
								&& entityRole.role.description.toLowerCase()
										.contains("organizer")) {
							authorized = true;
						}
					}
				if (!authorized)
					for (RoleInOrganization orgRole : topic.entity.organization.rolesAndUsers) {
						if (orgRole.user.id == userID
								&& orgRole.role.description.toLowerCase()
										.contains("lead")) {
							authorized = true;
						}
					}
				if (authorized) {
					duplicateMarks = DuplicateMark.find(
							"select dup from DuplicateMark dup where dup.marked.topic.id="
									+ topicID + " and dup.reviewed = false")
							.fetch();
				}
			}
		}
		render(authorized, topic, duplicateMarks);
	}

	/**
	 * @author AkrAmAtion
	 * 
	 *         sets a {@link DuplicateMark} as reviewed upon action of an
	 *         organizer
	 * 
	 * @param duplicateMarkID
	 *            is the id of the DuplicateMark to be reviewed.
	 * */
	public static void ignoreMark(long duplicateMarkID) {
		DuplicateMark dup = DuplicateMark.findById(duplicateMarkID);
		long topicID = -1;
		if (dup != null) {
			topicID = dup.original.topic.id;
			dup.reviewed = true;
			dup.save();
		}
		viewDuplicateMarks(topicID);
	}

	/**
	 * @author AkrAmAtion
	 * 
	 *         adds the idea that is proposed as the original idea to the list
	 *         of duplicateIdeas belonging to the marked idea in the
	 *         {@link DuplicateMark} specified by the duplicateMarkID and sets
	 *         the {@link DuplicateMark} as reviewed and accepted
	 * 
	 * @param duplicateMarkID
	 *            is the id of the {@link DuplicateMark} to be accepted by the
	 *            organizer
	 * */
	public static void acceptDuplicateMark(long duplicateMarkID) {
		DuplicateMark dup = DuplicateMark.findById(duplicateMarkID);
		Idea original = dup.original;
		Idea marked = dup.marked;
		if (marked.duplicateIdeas == null
				|| !marked.duplicateIdeas.contains(original)) {
			marked.addDuplicateIdea(original);
		}
		dup.accepted = true;
		dup.save();
		ignoreMark(duplicateMarkID);
	}

	/**
	 * block the user who made the {@link DuplicateMark} from further active
	 * participation on the system.
	 * 
	 * @param duplicateMarkID
	 *            the id of the DuplicateMark that the organizer uses to block
	 *            the Idea Developer
	 * @author AkrAmAtion
	 * 
	 * */
	public static void blockMarker(long duplicateMarkID) {
		DuplicateMark dup = DuplicateMark.findById(duplicateMarkID);
		if (dup != null) {
			// dup.marker.blocked = true;
			EEntity markEntity = dup.original.topic.entity;
			markEntity.blockedFromEntity.add(dup.marker);
			markEntity.save();
			dup.marker.blockedEntities.add(markEntity);
			dup.marker.save();
		}
		ignoreMark(duplicateMarkID);
	}

	/**
	 * @author Hesham Al-razaz
	 * 
	 * @param topicID
	 *            Topic ID
	 * 
	 *            this method locks the Topic
	 * 
	 */

	public static void lockTopic(long topicID) {
		Topic topic = Topic.findById(topicID);
		if (topic == null)
			return;
		else
			topic.lockTopic();

		viewTopic(topicID);

	}

	/**
	 * @author Hesham Al-razaz
	 * 
	 * @param topicID
	 *            Topic ID
	 * 
	 *            this method unlocks the Topic
	 * 
	 */
	public static void unlockTopic(long topicID) {
		Topic topic = Topic.findById(topicID);
		if (topic == null)
			return;
		else
			topic.unlockTopic();

		viewTopic(topicID);

	}

	/**
	 * This method is responsible for viewing all the idea developers in a given
	 * organization
	 * 
	 * @author shady
	 * 
	 * @param organizationID
	 *            The id of the organization
	 * 
	 * @view all idea developers in an organization
	 */
	public static void viewOrganizationIdeaDevelopers(long organizationID) {
		String userName = session.get("username");
		User user = User.find("userName", userName).first();

		if (user != null) {

			Organization organization = Organization.findById(organizationID);

			if (organization.isAsOrganizationLead(user.id)
					|| user.isOrganizationLead(organizationID)
					|| user.isSysteAdmin()) {

				if (organization != null
						&& organization.getIdeaDevelopers() != null) {
					List<User> ideaDevelopers = organization
							.getIdeaDevelopers();
					render(ideaDevelopers, organization);
				}
			}

		}

	}

	/**
	 * render the results of advanced search query to the view.
	 * 
	 * @param all
	 *            the value for which the user wants to get results that contain
	 *            words that match the whole set of words
	 * @param exactPhrase
	 *            the value for which the user wants to get results that contain
	 *            phrases exactly matching this value
	 * @param atleast
	 *            the value from which at least one word should appear in each
	 *            of the search results
	 * @param without
	 *            the value that should never appear in any of the returned
	 *            results
	 * @param tag
	 *            a comma-separated String with the tokens representing ids of
	 *            the {@link Tag} objects that each of the returned results
	 *            should match at least one of them
	 * @param specifyLocation
	 *            a {@link String} of value either "all" or "specific" denoting
	 *            the preference that the user has set regarding the search
	 *            location where the search results should be fetched from.
	 * @author AkrAmAtion
	 * @story C4S52
	 * */
	public static void advancedSearchResults(String all, String exactPhrase,
			String atleast, String without, String tag, String specifyLocation,
			String stDate, String endDate) {

		if (specifyLocation == null) {
			advancedSearch();
			return;
		}
		if (all == null)
			all = "";
		if (exactPhrase == null)
			exactPhrase = "";
		if (atleast == null)
			atleast = "";
		if (without == null)
			without = "";
		if (tag == null)
			tag = "";
		if (stDate == null || stDate.equals("")) {
			stDate = "2011-01-01";
		}
		if (endDate == null || endDate.equals("")) {
			endDate = "2050-12-31";
		}
		stDate = stDate.trim();
		endDate = endDate.trim();
		Date stDate_Date = new Date();
		Date endDate_Date = new Date();
		String DATE_FORMAT = "yyyy-MM-dd";
		SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
		try {
			stDate_Date = sdf.parse(stDate);
			endDate_Date = sdf.parse(endDate);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		all = all.trim().toLowerCase();
		String[] keysToFindAll = all.split(" ");
		atleast = atleast.trim().toLowerCase();
		String[] keysToFindAtLeast = atleast.split(" ");
		exactPhrase = exactPhrase.trim().toLowerCase();
		without = without.trim().toLowerCase();
		String[] keysToRemove = without.split(" ");
		for (int i = 0; i < keysToFindAll.length; i++) {
			keysToFindAll[i] = "%" + keysToFindAll[i] + "%";
		}
		for (int i = 0; i < keysToFindAtLeast.length; i++) {
			keysToFindAtLeast[i] = "%" + keysToFindAtLeast[i] + "%";
		}
		for (int i = 0; i < keysToRemove.length; i++) {
			keysToRemove[i] = "%" + keysToRemove[i] + "%";
		}
		if (!exactPhrase.equals("")) {
			exactPhrase = "%" + exactPhrase + "%";
		}
		if (!atleast.equals("")) {
			atleast = "%" + atleast + "%";
		}
		if (!without.equals("")) {
			without = "%" + without + "%";
		}
		String[] tagIds = tag.split(",");

		HashSet<Tag> tags = new HashSet<Tag>();
		for (String id : tagIds) {
			// System.out.println("tagId = " + id);
			if (!id.equals(""))
				tags.add((Tag) Tag.findById(Long.parseLong(id)));
		}
		boolean inAnyLocation = (specifyLocation.equalsIgnoreCase("all"));
		boolean inIdeas = params.getAll("inIdeas") != null || inAnyLocation;
		boolean inTopics = params.getAll("inTopics") != null || inAnyLocation;
		boolean inPlans = params.getAll("inPlans") != null || inAnyLocation;
		boolean inEntities = params.getAll("inEntities") != null
				|| inAnyLocation;
		boolean inOrganizations = params.getAll("inOrganizations") != null
				|| inAnyLocation;
		boolean inIdeaContent = params.getAll("inIdeaContent") != null;
		boolean inTopicDescription = params.getAll("inTopicDescription") != null;
		boolean noSelectingFieldSpecified = atleast.equals("")
				&& all.equals("") && exactPhrase.equals("");

		HashSet<Idea> ideaResults = new HashSet<Idea>();
		HashSet<Topic> topicResults = new HashSet<Topic>();
		HashSet<Plan> planResults = new HashSet<Plan>();
		HashSet<EEntity> entityResults = new HashSet<EEntity>();
		HashSet<Organization> organizationResults = new HashSet<Organization>();

		LinkedList<Idea> ideaResultsList = new LinkedList<Idea>();
		LinkedList<Topic> topicResultsList = new LinkedList<Topic>();
		LinkedList<Plan> planResultsList = new LinkedList<Plan>();
		LinkedList<EEntity> entityResultsList = new LinkedList<EEntity>();
		LinkedList<Organization> organizationResultsList = new LinkedList<Organization>();
		if (inIdeas || inIdeaContent) {
			HashSet<Idea> resultsExact = new HashSet<Idea>();
			HashSet<Idea> resultsAll = new HashSet<Idea>();
			HashSet<Idea> resultsatLeast = new HashSet<Idea>();
			HashSet<Idea> forbiddenResults = new HashSet<Idea>();

			if (!exactPhrase.equals("")) {
				if (!inIdeaContent)
					resultsExact
							.addAll((ArrayList) (Idea
									.find("select i from Idea i where lower(i.title) like ?"
											+ " and i.date >= ? and i.date <= ? and i.isHidden = false"
											+ " and i.topic.entity.organization.privacyStatus <> 2",
											exactPhrase, stDate_Date,
											endDate_Date).fetch()));
				resultsExact
						.addAll((ArrayList) (Idea
								.find("select i from Idea i where lower(i.content) like ?"
										+ " and i.date >= ? and i.date <= ? and i.isHidden = false"
										+ " and i.topic.entity.organization.privacyStatus <> 2",
										exactPhrase, stDate_Date, endDate_Date)
								.fetch()));
				if (!inIdeaContent) {
					HashSet<Comment> tempResults = new HashSet<Comment>();
					tempResults
							.addAll((ArrayList) Comment
									.find("select c from Comment c where lower(c.content) like ?"
											+ " and c.time >= ? and c.time <= ? and c.idea.isHidden = false"
											+ " and c.idea.topic.entity.organization.privacyStatus <> 2",
											exactPhrase, stDate_Date,
											endDate_Date).fetch());
					for (Comment c : tempResults) {
						resultsExact.add(c.idea);
					}
				}
			}
			if (!atleast.equals("")) {
				for (String keyWord : keysToFindAtLeast) {
					if (!inIdeaContent)
						resultsatLeast
								.addAll((ArrayList) (Idea
										.find("select i from Idea i where lower(i.title) like ?"
												+ " and i.date >= ? and i.date <= ? and i.isHidden = false"
												+ " and i.topic.entity.organization.privacyStatus <> 2",
												keyWord, stDate_Date,
												endDate_Date).fetch()));
					resultsatLeast
							.addAll((ArrayList) (Idea
									.find("select i from Idea i where lower(i.content) like ?"
											+ " and i.date >= ? and i.date <= ? and i.isHidden = false"
											+ " and i.topic.entity.organization.privacyStatus <> 2",
											keyWord, stDate_Date, endDate_Date)
									.fetch()));
					if (!inIdeaContent) {
						HashSet<Comment> tempResults = new HashSet<Comment>();
						tempResults
								.addAll((ArrayList) Comment
										.find("select c from Comment c where lower(c.content) like ?"
												+ " and c.time >= ? and c.time <= ? and c.idea.isHidden = false"
												+ " and c.idea.topic.entity.organization.privacyStatus <> 2",
												keyWord, stDate_Date,
												endDate_Date).fetch());
						for (Comment c : tempResults) {
							resultsatLeast.add(c.idea);
						}
					}
				}
			}
			if (!all.equals("")) {
				boolean firstTime = true;

				for (String keyWord : keysToFindAll) {
					HashSet<Idea> categoryResults = new HashSet<Idea>();
					if (!inIdeaContent)
						categoryResults
								.addAll((ArrayList) (Idea
										.find("select i from Idea i where lower(i.title) like ?"
												+ " and i.date >= ? and i.date <= ? and i.isHidden = false"
												+ " and i.topic.entity.organization.privacyStatus <> 2",
												keyWord, stDate_Date,
												endDate_Date).fetch()));
					categoryResults
							.addAll((ArrayList) (Idea
									.find("select i from Idea i where lower(i.content) like ?"
											+ " and i.date >= ? and i.date <= ? and i.isHidden = false"
											+ " and i.topic.entity.organization.privacyStatus <> 2",
											keyWord, stDate_Date, endDate_Date)
									.fetch()));
					if (!inIdeaContent) {
						HashSet<Comment> tempResults = new HashSet<Comment>();
						tempResults
								.addAll((ArrayList) Comment
										.find("select c from Comment c where lower(c.content) like ? "
												+ "and c.time >= ? and c.time <= ? and c.idea.isHidden = false"
												+ " and c.idea.topic.entity.organization.privacyStatus <> 2",
												keyWord, stDate_Date,
												endDate_Date).fetch());
						for (Comment c : tempResults) {
							categoryResults.add(c.idea);
						}
					}
					if (firstTime) {
						resultsAll.addAll(categoryResults);
					}
					for (Idea foundIdea : resultsAll) {
						if (!firstTime && !categoryResults.contains(foundIdea)) {
							resultsAll.remove(foundIdea);
						}
					}
					firstTime = false;
				}
			}
			if (!without.equals("")) {
				if (!inIdeaContent)
					for (String keyWord : keysToRemove)
						forbiddenResults
								.addAll((ArrayList) (Idea
										.find("select i from Idea i where lower(i.title) like ?"
												+ " and i.date >= ? and i.date <= ? and i.isHidden = false"
												+ " and i.topic.entity.organization.privacyStatus <> 2",
												keyWord, stDate_Date,
												endDate_Date).fetch()));
				for (String keyWord : keysToRemove)
					forbiddenResults
							.addAll((ArrayList) (Idea
									.find("select i from Idea i where lower(i.content) like ?"
											+ " and i.date >= ? and i.date <= ? and i.isHidden = false"
											+ " and i.topic.entity.organization.privacyStatus <> 2",
											keyWord, stDate_Date, endDate_Date)
									.fetch()));
				if (!inIdeaContent) {
					HashSet<Comment> tempResults = new HashSet<Comment>();
					for (String keyWord : keysToRemove)
						tempResults
								.addAll((ArrayList) Comment
										.find("select c from Comment c where lower(c.content) like ? "
												+ "and c.time >= ? and c.time <= ? and c.idea.isHidden = false"
												+ " and c.idea.topic.entity.organization.privacyStatus <> 2",
												keyWord, stDate_Date,
												endDate_Date).fetch());
					for (Comment c : tempResults) {
						forbiddenResults.add(c.idea);
					}
				}
			}
			HashSet<Idea> allTheResults = new HashSet<Idea>();
			allTheResults.addAll(resultsExact);
			allTheResults.addAll(resultsatLeast);
			allTheResults.addAll(resultsAll);
			ideaResults.addAll(allTheResults);
			if (noSelectingFieldSpecified) {
				// System.out.println("inIdeas.. No selecting field specified!");
				ideaResults
						.addAll((ArrayList) Idea
								.find("select i from Idea i where "
										+ "i.date >= ? and i.date <= ? and "
										+ "i.isHidden = false"
										+ " and i.topic.entity.organization.privacyStatus <> 2",
										stDate_Date, endDate_Date).fetch());
			}
			ideaResults.removeAll(forbiddenResults);

		}
		if (inTopics || inTopicDescription) {
			HashSet<Topic> resultsExact = new HashSet<Topic>();
			HashSet<Topic> resultsAll = new HashSet<Topic>();
			HashSet<Topic> resultsatLeast = new HashSet<Topic>();
			HashSet<Topic> forbiddenResults = new HashSet<Topic>();

			if (!exactPhrase.equals("")) {
				if (!inTopicDescription)
					resultsExact
							.addAll((ArrayList) (Topic
									.find("select t from Topic t where lower(t.name) like ?"
											+ " and t.date >= ? and t.date <= ? and t.status <> 4 and t.isDraft = false",
											exactPhrase, stDate_Date,
											endDate_Date).fetch()));
				resultsExact
						.addAll((ArrayList) (Topic
								.find("select t from Topic t where lower(t.description) like ?"
										+ " and i.date >= ? and i.date <= ? and t.status <> 4 and t.isDraft = false",
										exactPhrase, stDate_Date, endDate_Date)
								.fetch()));
			}
			if (!atleast.equals("")) {
				for (String keyWord : keysToFindAtLeast) {
					if (!inTopicDescription)
						resultsatLeast
								.addAll((ArrayList) (Topic
										.find("select t from Topic t where lower(t.name) like ?"
												+ " and t.date >= ? and t.date <= ? and t.status <> 4 and t.isDraft = false",
												keyWord, stDate_Date,
												endDate_Date).fetch()));
					resultsatLeast
							.addAll((ArrayList) (Topic
									.find("select t from Topic t where lower(t.description) like ?"
											+ " and t.date >= ? and t.date <= ? and t.status <> 4 and t.isDraft = false",
											keyWord, stDate_Date, endDate_Date)
									.fetch()));
				}
			}
			if (!all.equals("")) {
				boolean firstTime = true;

				for (String keyWord : keysToFindAll) {
					HashSet<Topic> categoryResults = new HashSet<Topic>();
					if (!inTopicDescription)
						categoryResults
								.addAll((ArrayList) (Idea
										.find("select t from Topic t where lower(t.name) like ?"
												+ " and t.date >= ? and t.date <= ? and t.status <> 4 and t.isDraft = false",
												keyWord, stDate_Date,
												endDate_Date).fetch()));
					categoryResults
							.addAll((ArrayList) (Topic
									.find("select t from Topic t where lower(t.description) like ?"
											+ " and t.date >= ? and t.date <= ? and t.status <> 4 and t.isDraft = false",
											keyWord, stDate_Date, endDate_Date)
									.fetch()));

					if (firstTime) {
						resultsAll.addAll(categoryResults);
					}
					for (Topic foundTopic : resultsAll) {
						if (!firstTime && !categoryResults.contains(foundTopic)) {
							resultsAll.remove(foundTopic);
						}
					}
					firstTime = false;
				}
			}
			if (!without.equals("")) {
				if (!inTopicDescription)
					for (String keyWord : keysToRemove)
						forbiddenResults
								.addAll((ArrayList) (Topic
										.find("select t from Topic t where lower(t.name) like ?"
												+ " and t.date >= ? and t.date <= ? and t.status <> 4 and t.isDraft = false",
												keyWord, stDate_Date,
												endDate_Date).fetch()));
				for (String keyWord : keysToRemove)
					forbiddenResults
							.addAll((ArrayList) (Topic
									.find("select t from Topic t where lower(t.description) like ?"
											+ " and t.date >= ? and t.date <= ? and t.status <> 4 and t.isDraft = false",
											keyWord, stDate_Date, endDate_Date)
									.fetch()));

			}
			HashSet<Topic> allTheResults = new HashSet<Topic>();
			allTheResults.addAll(resultsExact);
			allTheResults.addAll(resultsatLeast);
			allTheResults.addAll(resultsAll);
			topicResults.addAll(allTheResults);
			if (noSelectingFieldSpecified) {
				topicResults.addAll((ArrayList) Topic.find(
						"select t from Topic t where t.date >= ? and t.date <= ?"
								+ " and t.status <> 4 and t.isDraft = false",
						stDate_Date, endDate_Date).fetch());
			}
			topicResults.removeAll(forbiddenResults);

		}
		if (inPlans) {
			HashSet<Plan> resultsExact = new HashSet<Plan>();
			HashSet<Plan> resultsAll = new HashSet<Plan>();
			HashSet<Plan> resultsatLeast = new HashSet<Plan>();
			HashSet<Plan> forbiddenResults = new HashSet<Plan>();

			if (!exactPhrase.equals("")) {
				resultsExact.addAll((ArrayList) (Plan.find(
						"select p from Plan p where lower(p.title) like ?"
								+ " and p.startDate >= ? and p.startDate <= ?"
								+ " and p.endDate >= ? and p.endDate <= ?",
						exactPhrase, stDate_Date, endDate_Date, stDate_Date,
						endDate_Date).fetch()));
				resultsExact.addAll((ArrayList) (Plan.find(
						"select p from Plan p where lower(p.description) like ?"
								+ " and p.startDate >= ? and p.startDate <= ?"
								+ " and p.endDate >= ? and p.endDate <= ?",
						exactPhrase, stDate_Date, endDate_Date, stDate_Date,
						endDate_Date).fetch()));

			}
			if (!atleast.equals("")) {
				for (String keyWord : keysToFindAtLeast) {
					resultsatLeast
							.addAll((ArrayList) (Plan
									.find("select p from Plan p where lower(p.title) like ?"
											+ " and p.startDate >= ? and p.startDate <= ?"
											+ " and p.endDate >= ? and p.endDate <= ?",
											keyWord, stDate_Date, endDate_Date,
											stDate_Date, endDate_Date).fetch()));
					resultsatLeast
							.addAll((ArrayList) (Plan
									.find("select p from Plan p where lower(p.description) like ?"
											+ " and p.startDate >= ? and p.startDate <= ?"
											+ " and p.endDate >= ? and p.endDate <= ?",
											keyWord, stDate_Date, endDate_Date,
											stDate_Date, endDate_Date).fetch()));

				}
			}
			if (!all.equals("")) {
				boolean firstTime = true;

				for (String keyWord : keysToFindAll) {
					HashSet<Plan> categoryResults = new HashSet<Plan>();
					categoryResults
							.addAll((ArrayList) (Plan
									.find("select p from Plan p where lower(p.title) like ?"
											+ " and p.startDate >= ? and p.startDate <= ?"
											+ " and p.endDate >= ? and p.endDate <= ?",
											keyWord, stDate_Date, endDate_Date,
											stDate_Date, endDate_Date).fetch()));

					categoryResults
							.addAll((ArrayList) (Plan
									.find("select p from Plan p where lower(p.description) like ?"
											+ " and p.startDate >= ? and p.startDate <= ?"
											+ " and p.endDate >= ? and p.endDate <= ?",
											keyWord, stDate_Date, endDate_Date,
											stDate_Date, endDate_Date).fetch()));

					if (firstTime) {
						resultsAll.addAll(categoryResults);
					}
					for (Plan foundPlan : resultsAll) {
						if (!firstTime && !categoryResults.contains(foundPlan)) {
							resultsAll.remove(foundPlan);
						}
					}
					firstTime = false;
				}
			}
			if (!without.equals("")) {
				for (String keyWord : keysToRemove)
					forbiddenResults
							.addAll((ArrayList) (Plan
									.find("select p from Plan p where lower(p.title) like ?"
											+ " and p.startDate >= ? and p.startDate <= ?"
											+ " and p.endDate >= ? and p.endDate <= ?",
											keyWord, stDate_Date, endDate_Date,
											stDate_Date, endDate_Date).fetch()));

				for (String keyWord : keysToRemove)
					forbiddenResults
							.addAll((ArrayList) (Plan
									.find("select p from Plan p where lower(p.description) like ?"
											+ " and p.startDate >= ? and p.startDate <= ?"
											+ " and p.endDate >= ? and p.endDate <= ?",
											keyWord, stDate_Date, endDate_Date,
											stDate_Date, endDate_Date).fetch()));

			}
			HashSet<Plan> allTheResults = new HashSet<Plan>();
			allTheResults.addAll(resultsExact);
			allTheResults.addAll(resultsatLeast);
			allTheResults.addAll(resultsAll);
			planResults.addAll(allTheResults);
			if (noSelectingFieldSpecified) {
				planResults.addAll((ArrayList) Plan.find(
						"select p from Plan p where p.startDate >= ? and p.startDate <= ?"
								+ " and p.endDate >= ? and p.endDate <= ?",
						stDate_Date, endDate_Date, stDate_Date, endDate_Date)
						.fetch());
			}
			planResults.removeAll(forbiddenResults);
			for (Plan plan : planResults) {
				if (!plan.ideas.isEmpty()
						&& plan.ideas.get(0).topic.entity.organization.privacyStatus == 2) {
					continue;
				}
				boolean isTagged = tags.isEmpty();
				if (!isTagged)
					for (Idea planIdea : plan.ideas) {
						for (Tag planTag : planIdea.tags) {
							if (tags.contains(planTag)) {
								isTagged = true;
								break;
							}
						}
					}
				if (isTagged) {
					planResultsList.add(plan);
				}
			}

		}

		if (inEntities) {
			HashSet<EEntity> resultsExact = new HashSet<EEntity>();
			HashSet<EEntity> resultsAll = new HashSet<EEntity>();
			HashSet<EEntity> resultsatLeast = new HashSet<EEntity>();
			HashSet<EEntity> forbiddenResults = new HashSet<EEntity>();

			if (!exactPhrase.equals("")) {
				resultsExact.addAll((ArrayList) (EEntity.find(
						"select e from EEntity e where lower(e.name) like ?"
								+ " and e.organization.privacyStatus <> 2",
						exactPhrase).fetch()));
				resultsExact.addAll((ArrayList) (EEntity.find(
						"select e from EEntity e where lower(e.description) like ?"
								+ " and e.organization.privacyStatus <> 2",
						exactPhrase).fetch()));
			}
			if (!atleast.equals("")) {
				for (String keyWord : keysToFindAtLeast) {
					resultsatLeast.addAll((ArrayList) (EEntity.find(
							"select e from EEntity e where lower(e.name) like ?"
									+ " and e.organization.privacyStatus <> 2",
							keyWord).fetch()));
					resultsatLeast.addAll((ArrayList) (EEntity.find(
							"select e from EEntity e where lower(e.description) like ?"
									+ " and e.organization.privacyStatus <> 2",
							keyWord).fetch()));
				}
			}
			if (!all.equals("")) {
				boolean firstTime = true;

				for (String keyWord : keysToFindAll) {
					HashSet<EEntity> categoryResults = new HashSet<EEntity>();
					categoryResults.addAll((ArrayList) (EEntity.find(
							"select e from EEntity e where lower(e.name) like ?"
									+ " and e.organization.privacyStatus <> 2",
							keyWord).fetch()));
					categoryResults.addAll((ArrayList) (EEntity.find(
							"select e from EEntity e where lower(e.description) like ?"
									+ " and e.organization.privacyStatus <> 2",
							keyWord).fetch()));
					if (firstTime) {
						resultsAll.addAll(categoryResults);
					}
					for (EEntity foundEEntity : resultsAll) {
						if (!firstTime
								&& !categoryResults.contains(foundEEntity)) {
							resultsAll.remove(foundEEntity);
						}
					}
					firstTime = false;
				}
			}
			if (!without.equals("")) {
				for (String keyWord : keysToRemove)
					forbiddenResults.addAll((ArrayList) (EEntity.find(
							"select e from EEntity e where lower(e.name) like ?"
									+ " and e.organization.privacyStatus <> 2",
							keyWord).fetch()));
				for (String keyWord : keysToRemove)
					forbiddenResults.addAll((ArrayList) (EEntity.find(
							"select e from EEntity e where lower(e.description) like ?"
									+ " and e.organization.privacyStatus <> 2",
							keyWord).fetch()));

			}
			HashSet<EEntity> allTheResults = new HashSet<EEntity>();
			allTheResults.addAll(resultsExact);
			allTheResults.addAll(resultsatLeast);
			allTheResults.addAll(resultsAll);
			entityResults.addAll(allTheResults);
			if (noSelectingFieldSpecified) {
				entityResults
						.addAll((ArrayList) EEntity
								.find("select e from EEntity e where e.organization.privacyStatus <> 2")
								.fetch());
			}
			entityResults.removeAll(forbiddenResults);

		}

		if (inOrganizations) {
			HashSet<Organization> resultsExact = new HashSet<Organization>();
			HashSet<Organization> resultsAll = new HashSet<Organization>();
			HashSet<Organization> resultsatLeast = new HashSet<Organization>();
			HashSet<Organization> forbiddenResults = new HashSet<Organization>();

			if (!exactPhrase.equals("")) {
				resultsExact.addAll((ArrayList) (Organization.find(
						"select o from Organization o where lower(o.name) like ?"
								+ " and o.privacyStatus <> 2", exactPhrase)
						.fetch()));
				resultsExact.addAll((ArrayList) (Organization.find(
						"select o from Organization o where lower(o.description) like ?"
								+ " and o.privacyStatus <> 2", exactPhrase)
						.fetch()));
			}
			if (!atleast.equals("")) {
				for (String keyWord : keysToFindAtLeast) {
					resultsatLeast.addAll((ArrayList) (Organization.find(
							"select o from Organization o where lower(o.name) like ?"
									+ " and o.privacyStatus <> 2", keyWord)
							.fetch()));
					resultsatLeast.addAll((ArrayList) (Organization.find(
							"select o from Organization o where lower(o.description) like ?"
									+ " and o.privacyStatus <> 2", keyWord)
							.fetch()));
				}
			}
			if (!all.equals("")) {
				boolean firstTime = true;

				for (String keyWord : keysToFindAll) {
					HashSet<Organization> categoryResults = new HashSet<Organization>();
					categoryResults.addAll((ArrayList) (Organization.find(
							"select o from Organization o where lower(o.name) like ?"
									+ " and o.privacyStatus <> 2", keyWord)
							.fetch()));
					categoryResults.addAll((ArrayList) (Organization.find(
							"select o from Organization o where lower(o.description) like ?"
									+ " and o.privacyStatus <> 2", keyWord)
							.fetch()));
					if (firstTime) {
						resultsAll.addAll(categoryResults);
					}
					for (Organization foundOrganization : resultsAll) {
						if (!firstTime
								&& !categoryResults.contains(foundOrganization)) {
							resultsAll.remove(foundOrganization);
						}
					}
					firstTime = false;
				}
			}
			if (!without.equals("")) {
				for (String keyWord : keysToRemove)
					forbiddenResults.addAll((ArrayList) (Organization.find(
							"select o from Organization o where lower(o.name) like ?"
									+ " and o.privacyStatus <> 2", keyWord)
							.fetch()));
				for (String keyWord : keysToRemove)
					forbiddenResults.addAll((ArrayList) (Organization.find(
							"select o from Organization o where lower(o.description) like ?"
									+ " and o.privacyStatus <> 2", keyWord)
							.fetch()));

			}
			HashSet<Organization> allTheResults = new HashSet<Organization>();
			allTheResults.addAll(resultsExact);
			allTheResults.addAll(resultsatLeast);
			allTheResults.addAll(resultsAll);
			organizationResults.addAll(allTheResults);
			if (noSelectingFieldSpecified) {
				organizationResults
						.addAll((ArrayList) Organization
								.find("select o from Organization o where o.privacyStatus <> 2")
								.fetch());
			}
			organizationResults.removeAll(forbiddenResults);
		}

		for (Idea idea : ideaResults) {
			boolean isTagged = tags.isEmpty();
			if (!isTagged)
				for (Tag ideaTag : idea.tags) {
					if (tags.contains(ideaTag)) {
						isTagged = true;
						break;
					}
				}
			if (isTagged) {
				ideaResultsList.add(idea);
			}
		}

		for (Topic topic : topicResults) {
			boolean isTagged = tags.isEmpty();
			if (!isTagged)
				for (Tag ideaTag : topic.tags) {
					if (tags.contains(ideaTag)) {
						isTagged = true;
						break;
					}
				}
			if (isTagged) {
				topicResultsList.add(topic);
			}
		}

		entityResultsList.addAll(entityResults);
		organizationResultsList.addAll(organizationResults);

		render(ideaResultsList, topicResultsList, planResultsList,
				entityResultsList, organizationResultsList);
	}

	/**
	 * render the page testPage.html. Used for testing purposes only
	 * 
	 * @author AkrAmAtion
	 * */
	public static void testPage() {
		render();
	}

	/**
	 * get all the tags that contain the query q that is provided by the user
	 * searching for a certain tag. The method is called by the auto-complete
	 * box.
	 * 
	 * @param q
	 *            the query provided by the user and used for searching in Tags
	 * @author AkrAmAtion
	 * @story C4S52
	 * */
	public static void searchTag(String q) {
		List<Tag> result = Tag.find("byNameLike", "%" + q + "%").fetch();
		Gson gson = new Gson();
		JsonArray s = new JsonArray();
		for (Tag tag : result) {
			JsonObject temp = new JsonObject();
			temp.addProperty("id", tag.id);
			temp.addProperty("name", tag.name);
			s.add(temp);
		}
		String results = gson.toJson(s);
		renderJSON(results);
	}

	/**
	 * render the advanced Search form to the view advancedSearch.html.
	 * This feature is now available for any user (guests or registered)
	 * 
	 * @author AkrAmAtion
	 * */
	public static void advancedSearch() {
		String userName = session.get("username");
		boolean isLoggedin = true;
		//SUPPRESSING A FALSE CONDITION.. Advanced Search enabled now for everyone
		if (!isLoggedin)
		if (userName == null
				|| User.find("byUserName", userName).fetch().isEmpty()
				|| User.find("byUserName", userName).fetch().get(0) == null) {
			isLoggedin = false;
		}
		render(isLoggedin);
	}

	/**
	 * @author Omar Fouda
	 */

	public static void homePage() {
		render();
	}

	/**
	 * @author omar fouda
	 */
	public static void credits() {
		render();
	}

	/**
	 * Logs in a user manually by providing the username , this is for the sake
	 * of testing the controller methods that needs to get the username from the
	 * session
	 * 
	 * @param userNameToSet
	 *            the username of the user to log in
	 */
	public static void setUserName(String userNameToSet) {
		session.put("username", userNameToSet);
	}

	/**
	 * method to render the page with info about the site
	 * 
	 * @author omar fouda
	 */
	public static void about() {
		render();
	}

	/**
	 * remove a duplicate idea from the list of duplicate ideas of another one.
	 * 
	 * @param ideaID
	 *            the id of the idea of which the list of duplicates is to be
	 *            modified
	 * 
	 * @param duplicateID
	 *            the id of the duplicate idea that is to be removed from the
	 *            list of duplicate ideas
	 * 
	 * @story C4S59
	 * @author AkrAmAtion
	 * */
	public static void removeDuplicateIdea(long ideaID, long duplicateID) {
		Idea idea = Idea.findById(ideaID);
		if (idea != null) {
			Idea duplicate = Idea.findById(duplicateID);
			if (idea.duplicateIdeas.contains(duplicate)) {
				idea.duplicateIdeas.remove(duplicate);
				idea.save();
			}
		}
		viewIdea(ideaID);
	}

}